package com.wsl.config;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author:WangShuliang
 * @Description:
 * @Date:Created in 11:32 2018/1/8
 * @Modified by:
 */
@Component
@Aspect
public class WebControlllerAop {
    Log logger = LogFactory.getLog(WebControlllerAop.class);
    //匹配com.wsl.controller包及其包下的所有类的所有方法
    @Pointcut("execution(* com.wsl.controller..*.*(..))")
    public void executeService(){}

    /**
     * 方法被调用前执行
     * @param joinPoint
     */
    @Before("executeService()")
    public void doBeforeAdvice(JoinPoint joinPoint){
        System.out.println("我是前置通知");
        //获取目标方法的参数信息
        Object[] obj = joinPoint.getArgs();
        //Aop代理类的信息
        joinPoint.getThis();
        //代理的目标对象
        joinPoint.getTarget();
        //用的最多 通知大签名
        Signature signature = joinPoint.getSignature();
        //代理的是哪一个方法
        logger.info("代理的是哪一个方法"+signature.getName());
        //Aop代理类的名字
        logger.info("代理类的名字"+signature.getDeclaringTypeName());
        //Aop代理类的信息
        System.out.println(signature.getDeclaringType());
        //获取RequestAttributes
        RequestAttributes requestAttribute = RequestContextHolder.getRequestAttributes();

        //从获取的RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request =(HttpServletRequest)requestAttribute.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //如果要获取Session信息的话 可以这样写
        HttpSession session = (HttpSession)requestAttribute.resolveReference(RequestAttributes.REFERENCE_SESSION);
        Enumeration<String> enumeration = request.getParameterNames();
        Map parameterMap =new HashMap();
        while(enumeration.hasMoreElements()){
            String parameter = enumeration.nextElement();
            parameterMap.put(parameter,request.getParameter(parameter));
        }
       logger.info(parameterMap.toString());
    }

    /**
     * 后置最终通知
     */
   @After("executeService()")
    public void afterService(){
        logger.info("执行后置返回消息为。。。");
    }

    /**
     * 后置返回通知  这里需要注意的是：
     * 1 如果参数中的第一个参数为JoinPoint，则第二个参数返回值的信息
     * 2 如果参数中的第一个参数为JoinPoint，则第一个参数为returning中对应的参数
     *  returning 限定了只有目标方法返回值与通知方法返回值相应类型时才能执行后置返回通知，否则不执行，对于returning对应的通知方法参数为Object类型将
     *  匹配任何目标返回值
     * @param joinPoint
     * @param keys
     */
    @AfterReturning(value="executeService()",returning = "keys")
   public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){
       logger.info("第一个后置返回通知的返回值:"+keys);
   }

   @AfterReturning(value = "executeService()" ,returning = "keys",argNames = "keys")
   public void doAfterReturningAdvice2(String keys){
        logger.info("第二个后置通知的返回值:"+keys);
   }

    /**
     * 后置通知异常
     * 定义一个名字 改名字用于匹配通知实现方法的一个参数名，当目标方法抛出异常返回后，将把目标方法抛出的异常传递给通知方法
     *  throwing限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知 否则不执行  对于throwing对应的通知方法参数为Throwable
     *  类型将匹配任何异常。
     * @param joinPoint
     * @param exception
     */
   @AfterThrowing(value="executeService()",throwing = "exception")
   public  void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
       //目标方法名
        logger.info(joinPoint.getSignature().getName());
        if (exception instanceof  NullPointerException){
            logger.info("发生了空指针异常！！！！！！！");
        }
   }

   @Around("executeService()")
   public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
       logger.info("环绕通知的目标方法:"+proceedingJoinPoint.getSignature().getName());
       try {
            //o=obj之前可以写目标方法执行前的逻辑
           Object obj= proceedingJoinPoint.proceed();
           return  obj;

       }catch (Throwable throwable){
           throwable.printStackTrace();
       }
       return  null;
   }


























}